﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PrototypeZGame
{
    public class Human : Unit
    {
        public static int humanCount = 0;
        // Food level
        public float FL = 2400, maxFL = 2400;
        // Energy level
        public float EL = 200, maxEL = 200, ELRun = 2, ELRegenRate = 1;
        
        // Sleep level
        //public float SL = 2400, maxSL = 2400, sleepySL = 100;



        public Human(int X, int Y, World world)
            : base(X, Y, world)
        {
            tileType = TileType.Human;
            humanCount++;
            name = "Human_" + humanCount;

            handsReach = 1.5f;
            AP = 1.0f;
            APRegenRate = 1.0f;
            maxAP = 1.0f;
            APWalk = 1.0f;
            APRun = 0.5f;

            HP = 10;
            maxHP = 10;
            _baseAttackStrength = 2;

            viewDistance = 15.0f;

            inventory = new Inventory(world, 5);
            _blocking = Result.BlockingHuman;
        }

        public float _handEC = 2;

        public float attackEC
        {
            get 
            {
                Weapon weapon = inventory.rightHand as Weapon;
                if (weapon == null)
                {
                    return _handEC;
                }
                else
                {
                    return weapon.EC;
                }
            }

        }



        public override void Die()
        {
            base.Die();
            tileType = TileType.HumanBody;            
        }

        public override Result walk(Direction direction)
        {
            if (running && EL < ELRun)
            {
                return Result.NoEP;
            }
            Result ret = base.walk(direction);
            if (ret == Result.NoBlock)
            {
                if (running)
                {
                    EL -= ELRun;
                }
                return ret;
            }
            else
            {
                return ret;
            }
        }

        public override string getInfoString()
        {
            string ret = base.getInfoString()
                + "Food: " + FL + "/" + maxFL + "; "
                + "Energy: " + EL + "/" + maxEL + ";\n";
            if (inventory.rightHand != null)
            {
                ret+= inventory.rightHand.name + ": "+ inventory.rightHand.description + "\n";
            }
            return ret;
        }

        public override void newTurn()
        {
            base.newTurn();
            EL = Math.Min(EL + ELRegenRate, maxEL);

            FL -= 10;
        }

        public override bool Attack(Unit defender)
        {
            if (EL < attackEC)
            {
                return false;
            }

            if (base.Attack(defender))
            {
                EL -= attackEC;
                return true;
            }
            else
            {
                return false;
            }
        }

        public override Result useItem(int num)
        {
            if (num >= inventory.Count) return Result.OutOfRange;

            Weapon weapon = inventory.at(num) as Weapon;
            if (weapon != null)
            {
                inventory.wear(num);
                return Result.Success;
            }

            Food food = inventory.at(num) as Food;
            if (food != null)
            {
                if (AP < 1)
                {
                    return Result.NoAP;
                }
                food = inventory.takeFrom(num) as Food;
                FL = Math.Min(maxFL, FL + food.FV);
                HP = Math.Min(maxHP, HP + food.HPBonus);
                AP--;
                return Result.Success;
            }

            return Result.Success;
        }

        public List<Food> findFood()
        {
            List<Food> food = new List<Food>();
            Vec2 A = position - new Vec2((int)viewDistance);
            Vec2 B = position + new Vec2((int)viewDistance);
            if (A.x < 0) A.x = 0;
            if (A.y < 0) A.y = 0;
            if (B.x >= terrain.X) B.x = terrain.X - 1;
            if (B.y >= terrain.Y) B.y = terrain.Y - 1;

            Vec2 v = A;
            for (; v.x <= B.x; v.x++)
            {
                for (v.y = A.y; v.y <= B.y; v.y++)
                {
                    food.AddRange( terrain.getField(v).onFieldFood );
                }
            }

            return food;
        }

        public List<Weapon> findWeapon()
        {
            List<Weapon> weapon = new List<Weapon>();
            Vec2 A = position - new Vec2((int)viewDistance);
            Vec2 B = position + new Vec2((int)viewDistance);
            if (A.x < 0) A.x = 0;
            if (A.y < 0) A.y = 0;
            if (B.x >= terrain.X) B.x = terrain.X - 1;
            if (B.y >= terrain.Y) B.y = terrain.Y - 1;

            Vec2 v = A;
            for (; v.x <= B.x; v.x++)
            {
                for (v.y = A.y; v.y <= B.y; v.y++)
                {
                    weapon.AddRange(terrain.getField(v).onFieldWeapon);
                }
            }

            return weapon;
        }


        public EnemyStrength evaluateEnemiesStrength()
        {
            EnemyStrength ret;
            ret.s = 0;
            ret.v = new Vec2(0);

            Vec2 A = position - new Vec2(11);
            Vec2 B = position + new Vec2(11);
            if (A.x < 0) A.x = 0;
            if (A.y < 0) A.y = 0;
            if (B.x >= terrain.X) B.x = terrain.X - 1;
            if (B.y >= terrain.Y) B.y = terrain.Y - 1;
            
            float x = 0;
            float y = 0;
            Vec2 v = A;
            for (; v.x <= B.x; v.x++)
            {
                for (v.y = A.y; v.y <= B.y; v.y++)
                {
                    foreach (Zombie z in terrain.getField(v).onFieldZombies)
                    {
                        if (z.dead != true)
                        {
                            float distance = World.Distance(this, z);
                            ret.s += z.attackStrength * z.HP / (float)Math.Sqrt(Math.Sqrt( distance ));
                            x += (z.position.x - position.x) / distance;
                            y += (z.position.y - position.y) / distance;
                        }
                    }
                }
            }


            float m = Math.Max( Math.Abs(x), Math.Abs(y));

            x /= m;
            y /= m;
            x *= viewDistance - 1;
            y *= viewDistance - 1;

            ret.v.x = (int)x;
            ret.v.y = (int)y;

            return ret;
        }


        public float evaluateHumanStrength()
        {
            float ret = attackStrength * HP;
            if (inventory.rightHand == null)
            {
                ret *= 0.5f;
            }
            return ret;
        }


        public override void Draw()
        {
            base.Draw();
            if (inventory.rightHand != null)
            {
                Weapon weapon = inventory.rightHand as Weapon;
                if (weapon != null)
                {
                    Rectangle sourceRectangle = new Rectangle(((int)weapon.tileTypeMini % 16) * fieldResolution, fieldResolution * ((int)weapon.tileTypeMini / 16), fieldResolution, fieldResolution);
                    world.spriteBatch.Draw(tileset, destinationRectangle, sourceRectangle, Color.White);
                }
                
            }

        }

    }
}
